import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface, ValidatorOptions, registerDecorator } from 'class-validator';
import { ObjectType, DataSource, Repository, ObjectLiteral } from 'typeorm';
import { Injectable, Type } from '@nestjs/common';

type Condition = {
    entity: ObjectType<any>;
    /**
     * 用于查询的比对字段,默认id
     */
    map?: string;
};

@ValidatorConstraint({ name: 'isExist', async: true })
@Injectable()
export class ExistConstraint implements ValidatorConstraintInterface {
    constructor(
        protected dataSource: DataSource
    ) { }
    validate(value: any, args?: ValidationArguments): boolean | Promise<boolean> {
        let Repo: Repository<ObjectLiteral>
        let map: string = 'id'

        //对 传过来的 args.constraint[0] 进行分类

        if ('entity' in args.constraints[0])// args.constraint[0]为对象时
        {
            map = args.constraints[0].map || 'id'
            Repo = this.dataSource.getRepository(args.constraints[0].entity)
        }
        //不是对象直接是entity时
        else {
            Repo = this.dataSource.getRepository(args.constraints[0].entity)
        }

        const item = Repo.findOne({ where: { [map]: value } })
        return !!item
    }
    defaultMessage?(args?: ValidationArguments): string {
        if (!args.constraints[0]) {
            return 'Model not been specified!';
        }
        return `All instance of ${args.constraints[0].name} must been exists in databse!`;
    }
}

//函数的重载  实现签名 函数签名，实现签名不参加属性的使用2，参数都是通过函数签名来实现

function isExist(condition: ObjectType<any>, validatorOptions: ValidatorOptions): (obj: Record<string,any>, propertyName: string) => void
function isExist(condition: Condition, validatorOptions: ValidatorOptions): (obj: Record<string,any>, propertyName: string) => void
//实现签名
function isExist(condition: ObjectType<any> | Condition, validatorOptions: ValidatorOptions): (obj: Record<string,any>, propertyName: string) => void {
    return (obj: Record<string,any>, propertyName: string) => {
        registerDecorator({
            target: obj.constructor,
            propertyName,
            validator: ExistConstraint,
            constraints: [condition],
            options: validatorOptions

        })
    }
}
export { isExist };
